﻿
Imports System.Threading

Public Class now_t
    Public Shared ReadOnly [global] As now_t
    Private Shared ReadOnly maxInt32AsUint32 As UInt32 = maxInt32.asuint32()
    Private Shared ReadOnly maxInt32Plus1 As UInt32 = maxInt32AsUint32 + 1

    Shared Sub New()
        [global] = New now_t()
    End Sub

    Public Function ticks() As Int64
        If isdebugmode() Then
            Return hires_ticks()
        Else
            Return millisecondsToTicks(milliseconds())
        End If
    End Function

    Public Function lowres_ticks() As Int64
        Return DateTime.Now().Ticks()
    End Function

    Public Function hires_ticks() As Int64
        Return Global.hires_ticks()
    End Function

    Private Function currentMilliseconds() As UInt32
        Dim i As Int32 = 0
        i = environmentMilliseconds()
        If i < 0 Then
            i -= minInt32
            Return maxInt32AsUint32 + i
        Else
            Return i
        End If
    End Function

    Public Function environmentMilliseconds() As Int32
        Return Environment.TickCount()
    End Function

    Private offset As Int64 = 0
    Private lastMs As UInt32 = 0

    Private Sub reviseOffset()
        Dim t As Int64 = 0
        t = (ticksToMilliseconds(DateTime.Now().Ticks()) - currentMilliseconds()) -
            (currentMilliseconds() - ticksToMilliseconds(DateTime.Now().Ticks()))
        t >>= 1
        atomic.eva(offset, t)
    End Sub

    Private Sub New()
        reviseOffset()
    End Sub

    Public Function seconds() As Int64
        Return millisecondsToSeconds(milliseconds())
    End Function

    Public Function milliseconds() As Int64
        Dim c As UInt32 = 0
        c = currentMilliseconds()
        If c < (lastMs And maxInt32Plus1) Then
            reviseOffset()
        End If
        lastMs = c
        Dim rtn As Int64 = 0
        rtn = offset + c
        Return assert_return(rtn > 0, rtn)
    End Function
End Class

Public Module _now_t
    Public ReadOnly Now As now_t = Nothing

    Sub New()
        Now = now_t.global
    End Sub
End Module
